const sharp = require('sharp');
const path = require('path');
const fs = require('fs-extra');

class ImageProcessor {
  constructor() {
    // 支持的输入格式
    this.supportedInputFormats = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp', '.svg', '.ico'];
    // 支持的输出格式
    this.supportedOutputFormats = ['jpeg', 'png', 'webp', 'tiff', 'gif', 'bmp'];
  }

  /**
   * 处理单个图片
   * @param {string} inputPath - 输入文件路径
   * @param {string} outputFolder - 输出文件夹路径
   * @param {object} options - 处理选项
   * @returns {string} 输出文件路径
   */
  async processImage(inputPath, outputFolder, options) {
    const {
      format = null,
      quality = 80,
      width = null,
      height = null,
      maintainAspectRatio = true,
      prefix = '',
      suffix = '_processed'
    } = options;

    // 确保输出文件夹存在
    await fs.ensureDir(outputFolder);

    // 获取文件信息
    const inputFileName = path.basename(inputPath, path.extname(inputPath));
    const inputExt = path.extname(inputPath).toLowerCase();
    
    // 检查输入格式是否支持
    if (!this.supportedInputFormats.includes(inputExt)) {
      throw new Error(`不支持的输入格式: ${inputExt}`);
    }

    // 确定输出格式和文件名
    const outputFormat = format || this.getDefaultOutputFormat(inputExt);
    const outputFileName = `${prefix}${inputFileName}${suffix}.${outputFormat}`;
    const outputPath = path.join(outputFolder, outputFileName);

    try {
      // 创建sharp实例
      let image = sharp(inputPath);

      // 获取原始图片信息
      const metadata = await image.metadata();
      console.log(`处理图片: ${inputFileName}, 原始尺寸: ${metadata.width}x${metadata.height}`);

      // 图片裁剪
      if (options.enableCrop && options.cropOptions) {
        const cropArea = this.calculateCropArea(metadata, options.cropOptions);
        if (cropArea) {
          console.log(`裁剪区域: left=${cropArea.left}, top=${cropArea.top}, width=${cropArea.width}, height=${cropArea.height}`);
          image = image.extract(cropArea);
          
          // 更新metadata以反映裁剪后的尺寸
          metadata.width = cropArea.width;
          metadata.height = cropArea.height;
        }
      }

      // 尺寸调整
      if (width || height) {
        const resizeOptions = {
          fit: maintainAspectRatio ? 'inside' : 'fill',
          withoutEnlargement: false
        };

        // 计算实际像素值
        const actualWidth = this.calculateActualSize(width, metadata.width);
        const actualHeight = this.calculateActualSize(height, metadata.height);

        if (actualWidth && actualHeight) {
          // 指定了宽度和高度
          image = image.resize(actualWidth, actualHeight, resizeOptions);
        } else if (actualWidth) {
          // 只指定宽度，高度自动计算
          image = image.resize(actualWidth, null, resizeOptions);
        } else if (actualHeight) {
          // 只指定高度，宽度自动计算
          image = image.resize(null, actualHeight, resizeOptions);
        }
      }

      // 格式转换和质量设置
      switch (outputFormat.toLowerCase()) {
        case 'jpeg':
        case 'jpg':
          if (quality !== null && quality !== undefined) {
            image = image.jpeg({ quality: parseInt(quality) });
          } else {
            image = image.jpeg(); // 使用默认质量
          }
          break;
        case 'png':
          if (quality !== null && quality !== undefined) {
            // PNG使用压缩级别而不是质量
            const compressionLevel = Math.round((100 - quality) / 10);
            image = image.png({ compressionLevel: Math.max(0, Math.min(9, compressionLevel)) });
          } else {
            image = image.png(); // 使用默认压缩级别
          }
          break;
        case 'webp':
          if (quality !== null && quality !== undefined) {
            image = image.webp({ quality: parseInt(quality) });
          } else {
            image = image.webp(); // 使用默认质量
          }
          break;
        case 'tiff':
          if (quality !== null && quality !== undefined) {
            image = image.tiff({ quality: parseInt(quality) });
          } else {
            image = image.tiff(); // 使用默认质量
          }
          break;
        case 'gif':
          // GIF不支持质量设置，但可以优化
          image = image.gif();
          break;
        case 'bmp':
          image = image.bmp();
          break;
        default:
          throw new Error(`不支持的输出格式: ${outputFormat}`);
      }

      // 保存处理后的图片
      await image.toFile(outputPath);

      // 获取处理后的文件信息
      const outputStats = await fs.stat(outputPath);
      const inputStats = await fs.stat(inputPath);
      
      console.log(`图片处理完成: ${outputFileName}`);
      console.log(`文件大小: ${this.formatFileSize(inputStats.size)} -> ${this.formatFileSize(outputStats.size)}`);
      
      return outputPath;
    } catch (error) {
      throw new Error(`处理图片失败 ${inputFileName}: ${error.message}`);
    }
  }

  /**
   * 获取默认输出格式
   * @param {string} inputExt - 输入文件扩展名
   * @returns {string} 默认输出格式
   */
  getDefaultOutputFormat(inputExt) {
    const formatMap = {
      '.jpg': 'jpeg',
      '.jpeg': 'jpeg',
      '.png': 'png',
      '.gif': 'gif',
      '.bmp': 'bmp',
      '.tiff': 'tiff',
      '.webp': 'webp',
      '.svg': 'png', // SVG转换为PNG
      '.ico': 'png'  // ICO转换为PNG
    };
    
    return formatMap[inputExt.toLowerCase()] || 'jpeg';
  }

  /**
   * 格式化文件大小
   * @param {number} bytes - 字节数
   * @returns {string} 格式化后的文件大小
   */
  formatFileSize(bytes) {
    if (bytes === 0) return '0 Bytes';
    
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * 获取支持的格式列表
   * @returns {object} 支持的格式信息
   */
  getSupportedFormats() {
    return {
      input: this.supportedInputFormats,
      output: this.supportedOutputFormats
    };
  }

  /**
   * 计算实际尺寸（支持百分比）
   * @param {object|null} sizeValue - 尺寸值对象 {type: 'pixel'|'percentage', value: number}
   * @param {number} originalSize - 原始尺寸
   * @returns {number|null} 实际像素值
   */
  calculateActualSize(sizeValue, originalSize) {
    if (!sizeValue) return null;
    
    if (sizeValue.type === 'percentage') {
      return Math.round(originalSize * sizeValue.value / 100);
    } else if (sizeValue.type === 'pixel') {
      return sizeValue.value;
    }
    
    return null;
  }

  /**
   * 计算裁剪区域
   * @param {object} metadata - 图片元数据
   * @param {object} cropOptions - 裁剪选项
   * @returns {object|null} 裁剪区域 {left, top, width, height}
   */
  calculateCropArea(metadata, cropOptions) {
    const { ratio, position, customCrop } = cropOptions;
    const originalWidth = metadata.width;
    const originalHeight = metadata.height;

    let cropWidth, cropHeight, left, top;

    if (ratio === 'custom' && customCrop) {
      // 自定义裁剪
      left = Math.max(0, Math.min(customCrop.left, originalWidth - 1));
      top = Math.max(0, Math.min(customCrop.top, originalHeight - 1));
      cropWidth = Math.max(1, Math.min(customCrop.width, originalWidth - left));
      cropHeight = Math.max(1, Math.min(customCrop.height, originalHeight - top));
    } else {
      // 按比例裁剪
      const [ratioWidth, ratioHeight] = this.parseRatio(ratio);
      if (!ratioWidth || !ratioHeight) return null;

      // 计算裁剪尺寸
      const targetRatio = ratioWidth / ratioHeight;
      const currentRatio = originalWidth / originalHeight;

      if (currentRatio > targetRatio) {
        // 原图更宽，以高度为准
        cropHeight = originalHeight;
        cropWidth = Math.round(cropHeight * targetRatio);
      } else {
        // 原图更高，以宽度为准
        cropWidth = originalWidth;
        cropHeight = Math.round(cropWidth / targetRatio);
      }

      // 计算裁剪位置
      const cropPosition = this.calculateCropPosition(originalWidth, originalHeight, cropWidth, cropHeight, position);
      left = cropPosition.left;
      top = cropPosition.top;
    }

    // 确保裁剪区域在图片范围内
    left = Math.max(0, Math.min(left, originalWidth - cropWidth));
    top = Math.max(0, Math.min(top, originalHeight - cropHeight));
    cropWidth = Math.min(cropWidth, originalWidth - left);
    cropHeight = Math.min(cropHeight, originalHeight - top);

    return { left, top, width: cropWidth, height: cropHeight };
  }

  /**
   * 解析裁剪比例
   * @param {string} ratio - 比例字符串，如 "4:3"
   * @returns {array} [宽度比例, 高度比例]
   */
  parseRatio(ratio) {
    if (!ratio || ratio === 'custom') return [null, null];
    
    const parts = ratio.split(':');
    if (parts.length !== 2) return [null, null];
    
    const width = parseFloat(parts[0]);
    const height = parseFloat(parts[1]);
    
    if (isNaN(width) || isNaN(height) || width <= 0 || height <= 0) {
      return [null, null];
    }
    
    return [width, height];
  }

  /**
   * 计算裁剪位置
   * @param {number} originalWidth - 原图宽度
   * @param {number} originalHeight - 原图高度
   * @param {number} cropWidth - 裁剪宽度
   * @param {number} cropHeight - 裁剪高度
   * @param {string} position - 位置 ('center', 'top', 'bottom', 'left', 'right')
   * @returns {object} {left, top}
   */
  calculateCropPosition(originalWidth, originalHeight, cropWidth, cropHeight, position = 'center') {
    let left, top;

    switch (position) {
      case 'top':
        left = Math.round((originalWidth - cropWidth) / 2);
        top = 0;
        break;
      case 'bottom':
        left = Math.round((originalWidth - cropWidth) / 2);
        top = originalHeight - cropHeight;
        break;
      case 'left':
        left = 0;
        top = Math.round((originalHeight - cropHeight) / 2);
        break;
      case 'right':
        left = originalWidth - cropWidth;
        top = Math.round((originalHeight - cropHeight) / 2);
        break;
      case 'center':
      default:
        left = Math.round((originalWidth - cropWidth) / 2);
        top = Math.round((originalHeight - cropHeight) / 2);
        break;
    }

    return { left, top };
  }

  /**
   * 验证处理选项
   * @param {object} options - 处理选项
   * @returns {boolean} 是否有效
   */
  validateOptions(options) {
    const { format, quality, width, height } = options;

    // 验证输出格式
    if (format && !this.supportedOutputFormats.includes(format.toLowerCase())) {
      throw new Error(`不支持的输出格式: ${format}`);
    }

    // 验证质量参数
    if (quality !== undefined && (quality < 1 || quality > 100)) {
      throw new Error('质量参数必须在1-100之间');
    }

    // 验证尺寸参数
    if (width !== undefined && width !== null) {
      if (width.type === 'pixel' && (width.value < 1 || width.value > 10000)) {
        throw new Error('像素宽度必须在1-10000之间');
      } else if (width.type === 'percentage' && (width.value <= 0 || width.value > 1000)) {
        throw new Error('百分比宽度必须在0-1000%之间');
      }
    }

    if (height !== undefined && height !== null) {
      if (height.type === 'pixel' && (height.value < 1 || height.value > 10000)) {
        throw new Error('像素高度必须在1-10000之间');
      } else if (height.type === 'percentage' && (height.value <= 0 || height.value > 1000)) {
        throw new Error('百分比高度必须在0-1000%之间');
      }
    }

    return true;
  }
}

module.exports = ImageProcessor;